﻿#region using...
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Xml;
#endregion

namespace Infusion.Silverlight.Controls
{
    #region : Helper :
    public class Helper
    {
        #region Methods...
        #region CreateGridColumnDefinition...
        #region CreateGridColumnDefinition(double width)
        /// <summary>
        /// Creates a <see cref="System.Windows.Controls.ColumnDefinition"/> object with an absolute width.
        /// </summary>
        /// <param name="width">Width of the column in pixels.</param>
        /// <returns><see cref="System.Windows.Controls.ColumnDefinition"/> of a set width in pixels.</returns>
        public static ColumnDefinition CreateGridColumnDefinition(double width)
        {
            return CreateGridColumnDefinition(width, GridUnitType.Pixel);
        }
        #endregion

        #region CreateGridColumnDefinition(double width, GridUnitType gridUnitType)
        /// <summary>
        /// Creates a <see cref="System.Windows.Controls.ColumnDefinition"/> object
        /// </summary>
        /// <param name="width">Initial value of this instance of <see cref="System.Windows.GridUnitType"/></param>
        /// <param name="gridUnitType">The <see cref="System.Windows.GridUnitType"/> held by the instance of <see cref="System.Windows.GridLength"/> for this <see cref="System.Windows.Controls.ColumnDefinition"/></param>
        /// <returns><see cref="System.Windows.Controls.ColumnDefinition"/></returns>
        public static ColumnDefinition CreateGridColumnDefinition(double width, GridUnitType gridUnitType)
        {
            ColumnDefinition columnDefnition = new ColumnDefinition();
            columnDefnition.Width = new GridLength(width, gridUnitType);

            return columnDefnition;
        }
        #endregion
        #endregion

        #region CreateGridRowDefinition...
        #region CreateGridRowDefinition(double height)
        /// <summary>
        /// Creates a <see cref="System.Windows.Controls.RowDefinition"/> object with an absolute height.
        /// </summary>
        /// <param name="height">Height of the row in pixels.</param>
        /// <returns><see cref="System.Windows.Controls.RowDefinition"/> of a set height in pixels.</returns>
        public static RowDefinition CreateGridRowDefinition(double height)
        {
            return CreateGridRowDefinition(height, GridUnitType.Pixel);
        }
        #endregion

        #region CreateGridRowDefinition(double height, GridUnitType gridUnitType)
        /// <summary>
        /// Creates a <see cref="System.Windows.Controls.RowDefinition"/> object
        /// </summary>
        /// <param name="height">Initial value of this instance of <see cref="System.Windows.GridUnitType"/></param>
        /// <param name="gridUnitType">The <see cref="System.Windows.GridUnitType"/> held by the instance of <see cref="System.Windows.GridLength"/> for this <see cref="System.Windows.Controls.RowDefinition"/></param>
        /// <returns><see cref="System.Windows.Controls.RowDefinition"/></returns>
        public static RowDefinition CreateGridRowDefinition(double height, GridUnitType gridUnitType)
        {
            RowDefinition rowDefinition = new RowDefinition();
            rowDefinition.Height = new GridLength(height, gridUnitType);

            return rowDefinition;
        }
        #endregion
        #endregion

        #region GetChildByName
        /// <summary>
        /// Attempts to find a child object of a <see cref="System.Windows.DependencyObject"/> by it's <see cref="System.Windows.FrameworkElement.NameProperty"/>.
        /// </summary>
        /// <param name="reference">A <see cref="System.Windows.DependencyObject"/> to search.</param>
        /// <param name="name">The name of the child to be found.</param>
        /// <returns></returns>
        public static DependencyObject GetChildByName(DependencyObject reference, string name)
        {
            DependencyObject foundObj = null;

            int childrenCount = VisualTreeHelper.GetChildrenCount(reference);
            for (int i = 0; i < childrenCount; i++)
            {
                DependencyObject depObj = VisualTreeHelper.GetChild(reference, i);
                string thisName = depObj.GetValue(FrameworkElement.NameProperty).ToString();

                if (thisName == name)
                {
                    return depObj;
                }
                else
                {
                    foundObj = GetChildByName(depObj, name);
                }
            }

            return foundObj;
        }
        #endregion

        #region Segments...
        #region GenerateLineSegment
        /// <summary>
        /// Creates a <see cref="System.Windows.Media.LineSegment"/> object with a specified end <see cref="System.Windows.Point"/>.
        /// </summary>
        /// <param name="x">The x-coordinate value of the <see cref="System.Windows.Media.LineSegment"/>s <see cref="System.Windows.Point"/></param>
        /// <param name="y">The y-coordinate value of the <see cref="System.Windows.Media.LineSegment"/>s <see cref="System.Windows.Point"/></param>
        /// <returns></returns>
        public static LineSegment GenerateLineSegment(double x, double y)
        {
            LineSegment segment = new LineSegment();
            segment.Point = new Point(x, y);

            return segment;
        }
        #endregion

        #region GenerateArcSegment
        /// <summary>
        /// Creates a <see cref="System.Windows.Media.ArcSegment"/> object with the specified end <see cref="System.Windows.Point"/>, <see cref="System.Windows.Size"/> and <see cref="System.Windows.Media.SweepDirection"/>
        /// </summary>
        /// <param name="sweepDirection">The arc <see cref="System.Windows.Media.SweepDirection"/> specifying whether the arc is drawn <see cref="System.Windows.Media.SweepDirection.Clockwise"/> or <see cref="System.Windows.Media.SweepDirection.Counterclockwise"/></param>
        /// <param name="x">The x-coordinate value of the <see cref="System.Windows.Media.ArcSegment"/>s <see cref="System.Windows.Point"/></param>
        /// <param name="y">The y-coordinate value of the <see cref="System.Windows.Media.ArcSegment"/>s <see cref="System.Windows.Point"/></param>
        /// <param name="width">The initial width of the <see cref="System.Windows.Media.ArcSegment"/>s <see cref="System.Windows.Size"/></param>
        /// <param name="height">The initial height of the <see cref="System.Windows.Media.ArcSegment"/>s <see cref="System.Windows.Size"/></param>
        /// <returns></returns>
        public static ArcSegment GenerateArcSegment(SweepDirection sweepDirection, double x, double y, double width, double height)
        {
            ArcSegment segment = new ArcSegment();
            segment.SweepDirection = sweepDirection;
            segment.Point = new Point(x, y);
            segment.Size = new Size(width, height);
            segment.IsLargeArc = false;

            return segment;
        }
        #endregion
        #endregion

        #region HexToColor
        public static Color HexToColor(string hex)
        {
            if (hex.StartsWith("#"))
                hex = hex.Substring(1);

            long a, r, g, b;
            long num = long.Parse(hex, NumberStyles.HexNumber);

            if (hex.Length == 6)
            {
                a = 255;
                r = (num & 0xFF0000) >> 16;
                g = (num & 0xFF00) >> 8;
                b = num & 0xFF;
            }
            else if (hex.Length == 8)
            {
                a = (num & 0xFF000000) >> 24;
                r = (num & 0xFF0000) >> 16;
                g = (num & 0xFF00) >> 8;
                b = num & 0xFF;
            }
            else
            {
                throw new ArgumentOutOfRangeException("Hexidecimal color must be 6 or 8 characters long.");
            }

            return Color.FromArgb((byte)a, (byte)r, (byte)g, (byte)b);
        }
        #endregion

        #region GetBrush
        public static Brush GetBrush(Enum brush)
        {
            Brush brushObj = null;

            using (XmlReader reader = XmlReader.Create(new StringReader(Resources.Brushes)))
            {
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Element &&
                        (reader.Name == "SolidColorBrush" || reader.Name == "LinearGradientBrush" || reader.Name == "RadialGradientBrush"))
                    {
                        string brushType = reader.Name;
                        string name;

                        if (reader.MoveToAttribute("Name"))
                            name = reader.Value;
                        else
                            throw new Exception(string.Format("Brushes.xml includes a {0} without a name.", brushType));

                        if (name == brush.ToString())
                        {
                            switch (brushType)
                            {
                                case "SolidColorBrush":
                                    {
                                        string colorHex;

                                        if (reader.MoveToAttribute("Color"))
                                            colorHex = reader.Value;
                                        else
                                            throw new Exception(string.Format("SolidColorBrush '{0}' is missing its Color attribute.", name));

                                        brushObj = new SolidColorBrush(Helper.HexToColor(colorHex));
                                        break;
                                    }
                                case "LinearGradientBrush":
                                    {
                                        brushObj = new LinearGradientBrush();

                                        if (reader.MoveToAttribute("StartPoint"))
                                            ((LinearGradientBrush)brushObj).StartPoint = ParsePoint(reader.Value);

                                        if (reader.MoveToAttribute("EndPoint"))
                                            ((LinearGradientBrush)brushObj).EndPoint = ParsePoint(reader.Value);

                                        ((LinearGradientBrush)brushObj).GradientStops = ProcessGradientStops(brushType, reader);
                                        break;
                                    }
                                case "RadialGradientBrush":
                                    {
                                        brushObj = new RadialGradientBrush();

                                        if (reader.MoveToAttribute("GradientOrigin"))
                                            ((RadialGradientBrush)brushObj).GradientOrigin = ParsePoint(reader.Value);

                                        if (reader.MoveToAttribute("Center"))
                                            ((RadialGradientBrush)brushObj).Center = ParsePoint(reader.Value);

                                        if (reader.MoveToAttribute("RadiusX"))
                                            ((RadialGradientBrush)brushObj).RadiusX = Convert.ToDouble(reader.Value);

                                        if (reader.MoveToAttribute("RadiusY"))
                                            ((RadialGradientBrush)brushObj).RadiusY = Convert.ToDouble(reader.Value);

                                        ((RadialGradientBrush)brushObj).GradientStops = ProcessGradientStops(brushType, reader);
                                        break;
                                    }
                            }

                            break;
                        }
                    }
                }
            }

            return brushObj;
        }
        #endregion

        #region ProcessGradientStops
        private static GradientStopCollection ProcessGradientStops(string brushType, XmlReader reader)
        {
            GradientStopCollection stopCollection = new GradientStopCollection();

            bool processedStops = false;
            while (!processedStops)
            {
                reader.Read();
                if (reader.Name == "GradientStop")
                {
                    GradientStop gradientStop = new GradientStop();

                    if (reader.MoveToAttribute("Offset"))
                        gradientStop.Offset = double.Parse(reader.Value);

                    if (reader.MoveToAttribute("Color"))
                        gradientStop.Color = Helper.HexToColor(reader.Value);

                    stopCollection.Add(gradientStop);
                }

                if (reader.Name == brushType && reader.NodeType == XmlNodeType.EndElement)
                    processedStops = true;
            }

            return stopCollection;
        }
        #endregion

        #region ParsePoint
        public static Point ParsePoint(string pointAsString)
        {
            string xStr = pointAsString.Substring(0, pointAsString.IndexOf(","));
            string yStr = pointAsString.Substring(pointAsString.IndexOf(",") + 1);

            return new Point(double.Parse(xStr), double.Parse(yStr));
        }
        #endregion

        #region WriteDebugLine
        public static void WriteDebugLine(string message)
        {
            Debug.WriteLine(string.Format("{0}: {1}", DateTime.Now.ToString("HH:mm:ss.fff"), message));
        }
        #endregion

        #region CreateGradientStopCollection
        public static GradientStopCollection CreateGradientStopCollection(Dictionary<double, Color> gradientStops)
        {
            GradientStopCollection collection = new GradientStopCollection();

            foreach (double dictionaryItem in gradientStops.Keys)
            {
                GradientStop gradientStop = new GradientStop();
                gradientStop.Color = gradientStops[dictionaryItem];
                gradientStop.Offset = dictionaryItem;

                collection.Add(gradientStop);
            }

            return collection;
        }
        #endregion
        #endregion
    }
    #endregion
}